package com.welike.shibo.utils;

import com.welike.shibo.enums.TokenStatus;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author fangyu
 * @version v1.0.0
 * @since 2019-08-18 22:43
 */
@Component(value = "jwtUtil")
public class JwtUtil {

    /**
     * 加密秘钥
     */
    private String secret = "a1g2y47dg3dj59fjhhsd7cnewy73j";


    /**
     * 放入user信息，生成带user信息的token
     * @param user
     * @return String
     */
    public String generateToken(String user){
        Map<String, Object> claims = new HashMap<String, Object>(1);
        claims.put("sub", user);
        return generateToken(claims);
    }

    /**
     * 生成token
     * @param claims
     * @return String
     */
    private String generateToken(Map<String, Object> claims){
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(this.generateExpirationDate())
                .setIssuedAt(this.generateCurrentDate())
                .signWith(SignatureAlgorithm.HS512, this.secret)
                .compact();
    }

    /**
     * 获取当前时间
     * @return Date
     */
    private Date generateCurrentDate(){
        return new Date(System.currentTimeMillis());
    }

    /**
     * 设置token有效时间
     * @return Date
     */
    private Date generateExpirationDate() {
        // 设置为30天
        long expiration = (long) 30 * 24 * 60 * 60 * 1000;
        return new Date(System.currentTimeMillis() + expiration);
    }

    /**
     * 判断token是否可用刷新
     */
    public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(this.secret)
                    .parseClaimsJws(token)
                    .getBody();
            final Date iat = claims.getIssuedAt();
            final Date exp = claims.getExpiration();
            // 如果iat(生成token时间）早于 -最后生成token时间 或者 exp(token过期时间) 早于 当前时间，则返回false
//            if (iat.before(lastPasswordReset) || exp.before(generateCurrentDate())) {
//                return false;
//            }
//            return true;
            // 如果iat不早于最后生成时间 并且 exp不早于当前时间
            return !iat.before(lastPasswordReset) && !exp.before(generateCurrentDate());
        } catch (Exception e){
            return false;
        }
    }

    /**
     * 刷新token
     * @param token
     * @return String
     */
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            final Claims claims = Jwts.parser()
                    .setSigningKey(this.secret)
                    .parseClaimsJws(token)
                    .getBody();
            refreshedToken = this.generateToken(claims);
        } catch (Exception e){
            refreshedToken = null;
        }
        return refreshedToken;
    }

    /**
     * 校验token
     * @param token
     * @return TokenStatus
     */
    public TokenStatus verifyToken(String token) {
        TokenStatus result;
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(this.secret)
                    .parseClaimsJws(token)
                    .getBody();
            final Date exp = claims.getExpiration();
            // 如果 exp(token过期时间) 早于当前时间, 则token已过期
            if (exp.before(generateCurrentDate())) {
                result = TokenStatus.EXPIRED;
            } else {
                // 否则token 有效
                result = TokenStatus.VALID;
            }
        } catch (Exception e){
            // token 无效
            result = TokenStatus.INVALID;
        }
        return result;
    }

    /**
     * 获取用户编号
     * @param token
     * @return String
     */
    public String getUserNameFromToken(String token) {
        String userName;
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(this.secret)
                    .parseClaimsJws(token)
                    .getBody();
            userName = claims.getSubject();
        } catch (Exception e){
            userName = null;
        }
        return userName;
    }
}
